让我们看一下Spring如何定义关键的切点的概念。

12.2.1 Concepts

Spring的切点模型可以让切点在不同的通知类型中重用。你可以为不同的通知绑定相同的切点。
org.springframework.aop.Pointcut就是核心的接口,用来为特定的类和方法设置通知。下面就是这个接口:

public interface Pointcut {

    ClassFilter getClassFilter();

    MethodMatcher getMethodMatcher();

}

Pointcut接口分为两部分,分别用来对类和方法匹配,这两部分可以细粒度的组合(比如让两个结合使用)。
ClassFilter接口将切点限制在特定的目标类上。如果matcher()方法总是返回true,那么就是匹配所有的类:

public interface ClassFilter {

    boolean matches(Class clazz);
}

MethodMatcher接口通常更重要。完整的接口如下:

public interface MethodMatcher {

    boolean matches(Method m, Class targetClass);

    boolean isRuntime();

    boolean matches(Method m, Class targetClass, Object[] args);
}

matches(Method, Class)方法用来测试切点是否匹配目标类上的特定方法。可以在AOP代理创建的时候执行这个评估,避免每次方法调用时都需要测验。如果对于给定的方法,2个参数的matches方法返回了true,并且MethodMatcher的isRuntime()返回了true,那么每次方法调用时3个参数的mathes方法会被调用。这使得切点可以在通知执行前立即查看传递给方法的参数。
大多数MethodMatcher是静态的,这意味他们的isRuntime()方法是返回false。在这种情况下,3个参数的matches方法将永远不会被调用。

如果可能,尽量让pointcuts是静态的,AOP框架会在AOP代理创建的时候缓存切点评估的结果。

12.2.2 Operations on pointcuts

Spring支持对切点的操作:特别熟,unionintersection
Union意味着需要匹配至少一个切点。 Intersection以为这需要匹配全部的切点。 Union通常更有用。
切点可以由org.springframework.aop.support.Pointcuts类中的静态方法组成,或是用同一个包下的ComposablePointcut类。然而,使用AspectJ切点表达式通常是更简单的方式。

12.2.3 AspectJ expression pointcuts

从2.0起,Spring使用的最主要的切点类型就是org.springframework.aop.aspectj.AspectJExpressionPointcut。它用AspectJ提供的库解析AspectJ切点表达式字符串。
有关支持AspectJ切点的讨论,请看上一章。

12.2.4 Convenience pointcut implementations

Spring提供了一些便利的pointcut的实现。一些可以拿来直接使用;另一些被用来子类化成特定应用的切点。

static pointcuts

静态的切点是基于方法和目标累的,无法考虑方法的参数。大多是情况下,静态的切点足够了,并且也是最好的选择。静态的切点能只被Spring评估一次,在一个方法第一次被调用时:在这之后,每次方法被调用时不再需要评估。
让我们看一些Spring内部的一些静态pointcut的实现。

Regular expression pointcuts

指定静态切点很常见的方法是用正则表达式。Spring之外的一些AOP框架实现了这一点。
org.springframework.aop.support.JdkRegexpMethodPointcut是一个常用的正则表达式切点,使用了JDK1.4+对正则表达式提供的支持。
使用JdkRegexpMethodPointcut时,你可以设置字符串样式列表。如果列表中有一个匹配成功,切点的评估就会返回true。(因此这是对这些切点的有效的union。)
用法如下:

<bean id="settersAndAbsquatulatePointcut"
        class="org.springframework.aop.support.JdkRegexpMethodPointcut">
    <property name="patterns">
        <list>
            <value>.*set.*</value>
            <value>.*absquatulate</value>
        </list>
    </property>
</bean>

Spring提供了一个方便的类,RegexpMethodPointcutAdvisor,允许我们引用一个通知(请记住通知是一个拦截器,before advice,throws advice等)。本质上,还是使用了JdkRegexpMethodPointcut。使用RegexpMethodPointcutAdvisor把切点和通知封装到了一个bean中,简化了二者的联系,像下面这样:

<bean id="settersAndAbsquatulateAdvisor"
        class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice">
        <ref bean="beanNameOfAopAllianceInterceptor"/>
    </property>
    <property name="patterns">
        <list>
            <value>.*set.*</value>
            <value>.*absquatulate</value>
        </list>
    </property>
</bean>

RegexpMethodPointcutAdvisor适用于任何类型的通知。

Attribute-driven pointcuts

一个重要的静态切点的类型是metadata-driven切点。它使用了元数据的属性值:通常是源码级别的元数据。

Dynamic pointcuts

动态切点的评估过程比静态的花费要高。它们除了静态信息之外,还可以考虑方法的参数。这意味每次方法调用的时候他们都需要评估;因为参数是变化的,所以结果无法被缓存。
最主要的例子就是control flow切点。

Control flow pointcuts

Spring的control flow切点和AspectJ的cflow切点的概念是相似的,虽然它的功能较弱。(目前没有办法指定一个切点在另一个切点匹配的连接点下执行。)一个control flow切点会匹配当前的调用栈。比如,当一个连接点被com.mycompany.web.package包的一个方法调用或是被SomeCaller类调用,可能会触发它。Control flow切点需要用org.springframework.aop.support.ControllerFlowPointcut类。

与其他动态切点相比,Control flow切点在运行时评估的代价更巨大。在Java1.4中,它的花费大约是其他动态切点的五倍。

12.2.5 Pointcut superclasses

Spring提供了有用的pointcut父类来帮你实现自己的切点。
由于静态切点是最常用的,你可以像下列这样子类化StaticMethodMatcherPointcut。这只需要实现一个抽象方法(尽管重写其他方法也是可行的):

class TestStaticPointcut extends StaticMethodMatcherPointcut {

    public boolean matches(Method m, Class targetClass) {
        // return true if custom criteria match
    }
}

Spring也提供了动态切点的父类。
你可以在Spring 1.0 RC2及更高版本中使用任何通知类型的自定义切点。

12.2.6 Custom pointcuts

由于Spring AOP中的切点是Java类,而不是其他语言的特性(像AspectJ)。无论是静态还是动态的,都可以声明自定义的切点。Spring中自定义的切点任意的复杂。但是,如果可能的话还是建议使用AspectJ切点表达式。

之后版本的Spring也许会提供“语义切入点”,像JAC所提供的:例如,“目标对象中所有更改实例变量的所有方法。”